'''
This application is used to evaluate the performance of the solution:

1. latency with x(path), y(delay), 3pics, dense, sparse, trace
2. packet  with x(path), y(packet), 3pics, dense, sparse, trace
'''
import os, random, datetime, subprocess, time, math
import sys
SUMOTOOL = '/opt/sumo/sumo-0.17.1/tools'
sys.path.append(SUMOTOOL)
sys.path.append('/opt/sumo/sumo-0.17.1/bin')
import sumolib
import trace

class EstSimu:
    def __init__(self, netf, tracef):
        self.TRANGE = 100
        print "loading..."
        self._tracef = tracef
        self._netf = netf
        self._net = sumolib.net.readNet(self._netf)
        self._trace = trace.readTrace(self._tracef)
        print "done..."
            
    def GroundTruth(self, traced, roadName, time, window):        
        lowb = traced[0].getTime()
        highb = traced[len(traced)-1].getTime()
        
        if time + window / 2 > highb:
            lowb = highb - window
        elif time - window / 2 < lowb:
            highb = lowb + window
        else:
            lowb = time - int(window / 2)
            highb = lowb + window
        # end if
        
        #print "low = %d, high = %d, time = %d, window = %d" % (lowb, highb, time, window)
        
        # for each frame, find the average speed
        tframe = 0
        tavg = 0
        for tm in range(lowb, highb):
            if tm not in traced: continue
            tmframe = traced[tm]
            if not tmframe.hasRoad(roadName): continue
            roadSnap = tmframe.getRoad(roadName)
            speedlist = [v.getSpeed() for v in roadSnap.getVehicles().values()]
            tframe += 1
            tavg += sum(speedlist) / float(len(speedlist))
        #end for
        if tframe == 0:
            return  
        return tavg / tframe
        
    def AverageSpeed(self, roadInfo, roadSnap):
        avs = 0
        total = 0
        num = 0
        for v in roadSnap.getVehicles().values():
            total += v.getSpeed()
            num += 1
        #end for
        avs = total / num
        #handle special case
        varray = list() 
        varray = roadSnap.getVehicles().values()
        varray.sort(key=lambda v : v.getPos())
        
        if len(varray) == 1:
            avs = roadInfo.getSpeed()
        else:
            for i in range(0, len(varray)-1) :
                dis = varray[i+1].getPos() - varray[i].getPos()
                if dis > self.TRANGE:
                    avs = roadInfo.getSpeed()
            #end for
        #endif
        if avs < 0.001: avs = 0.1
        
        return avs

    def EstimateSpeed(self, roadInfo, roadSnap): 
        total = 0
        num = 0;
        X = 0   #average distance

        varray = list() 
        varray = roadSnap.getVehicles().values()
        varray.sort(key=lambda v : v.getPos())
        
        if len(varray) < 2:
            X = self.TRANGE
        else:
            total = 0
            for i in range(0, len(varray)-1) :
                dis = varray[i+1].getPos() - varray[i].getPos()
                total += dis
            #end for
            side = varray[0].getPos()
            if side > self.TRANGE:
                total += side
                num += 1
            side =  roadInfo.getLength() - varray[len(varray)-1].getPos()
            if side > self.TRANGE:
                total += side
                num += 1
            X = total / (len(varray)-1)
        #end if

        # now estimate using formulation
        if X  < 0.01: X = 1
        vm = roadInfo.getSpeed()
        est = vm * math.exp(-(vm+10)/X)
    
        # in case devide by zero
        if est < 0.001: est = 0.1
        
        return est

def EvalSimuSpeed(type):
    if type == 'trace':
        path = '/Users/hezongjian/Documents/texsrc/Traffic/simu/trace/'
        simu = EstSimu(path +'cologne.net.xml', path + 'netstate.xml')
    else:
        path = '/Users/hezongjian/Documents/texsrc/Traffic/simu/testbed/'
        simu = EstSimu(path +'testbed.net.xml', path + type +'.netstate.xml')
    
    orst = []
    for tf in range(5, 200, 10):
        irst = []
        while (len(irst) < 50):
            # select a random snapshot
            rSnap = random.choice(simu._trace.getSnapshots())
            # select a random road
            rRoadName = random.choice(rSnap.getEdges().keys())
            if rRoadName.startswith(":"): continue
            
            rRoadInfo = simu._net.getEdge(rRoadName)
            rRoadSnap = rSnap.getEdges()[rRoadName]
            
            gts = simu.GroundTruth(simu._trace.getSnapshots(), rRoadName, rSnap.getTime(), tf)
            es =  simu.EstimateSpeed(rRoadInfo, rRoadSnap)
            avs =  simu.AverageSpeed(rRoadInfo, rRoadSnap)
            irst.append([gts, es, avs])
        #end while
        # calculate the deviation
        print irst
        opt = [tf, 0, 0]
        for p in irst:
            opt[1] += (p[1] - p[0]) * (p[1] - p[0])
            opt[2] += (p[2] - p[0]) * (p[2] - p[0])
        # end for
        opt[1] = opt[1] / float(len(irst))
        opt[2] = opt[2] / float(len(irst))
        orst.append(opt)
    #end for    
    # save to file
    # print orst
    with open('./se.' + type+ '.txt', 'w') as f:
        for v in orst:
            opt = "%d, %f, %f\r\n" % (v[0], v[1], v[2])
            print opt,
            f.write(opt)


'''
WARNING: if you want to run this function, copy SpeedEval.py and trace.py to the testbed directory
I don't know why...
'''            
def EvalDensity():
    path = '/Users/hezongjian/Documents/texsrc/Traffic/simu/testbed/'
    os.chdir(path)
    
    orst = []
    for d in range(1, 20, 2):
        cdensity = d / float(10.0)
        ## generate dense random trace
        print cdensity
        cmds = ['python', SUMOTOOL +'/trip/randomTrips.py', '-p', str(cdensity), '-n', path + 'testbed.net.xml', '-r', path +'testbed.rou.xml']
        subprocess.call(cmds)
        ## generate trace file
        cmds = ['sumo', '-e', '500', '-n', path + 'testbed.net.xml', '-r', path + 'testbed.rou.xml', '--tripinfo-output', path + 'var.tripinfo.xml', '--netstate-dump', path + 'var.netstate.xml']
        subprocess.call(cmds)
        
        simu = EstSimu(path +'testbed.net.xml', path +'var.netstate.xml')
    
        irst = []
        while (len(irst) < 50):
            # select a random snapshot
            rSnap = random.choice(simu._trace.getSnapshots())
            # select a random road
            rRoadName = random.choice(rSnap.getEdges().keys())
            if rRoadName.startswith(":"): continue
            
            rRoadInfo = simu._net.getEdge(rRoadName)
            rRoadSnap = rSnap.getEdges()[rRoadName]
            
            gts = simu.GroundTruth(simu._trace.getSnapshots(), rRoadName, rSnap.getTime(), 60)
            es =  simu.EstimateSpeed(rRoadInfo, rRoadSnap)
            avs =  simu.AverageSpeed(rRoadInfo, rRoadSnap)
            irst.append([gts, es, avs])
        #end while    

        # calculate the deviation
        print irst
        opt = [cdensity, 0, 0]
        for p in irst:
            opt[1] += (p[1] - p[0]) * (p[1] - p[0])
            opt[2] += (p[2] - p[0]) * (p[2] - p[0])
        # end for
        opt[1] = opt[1] / float(len(irst))
        opt[2] = opt[2] / float(len(irst))
        orst.append(opt)
    #end for
    # save to file
    # print orst
    with open('./se.var.txt', 'w') as f:
        for v in orst:
            opt = "%f, %f, %f\r\n" % (v[0], v[1], v[2])
            print opt,
            f.write(opt)
#end def
        
        

def main():
    print "hello";
    #EvalSimuSpeed('dense')
    #EvalSimuSpeed('sparse')
    #EvalSimuSpeed('trace')
    EvalDensity()


if __name__ == "__main__":
    start = time.clock()
    random.seed(1234)
    main()
    elapsed = (time.clock() - start)
    print "Time used: %.2f" % elapsed